From 396acf3bbbe00a192cb0ea0a9ccf91b1d8d2850b Mon Sep 17 00:00:00 2001
From: Fuwn <50817549+Fuwn@users.noreply.github.com>
Date: Sat, 24 Jan 2026 13:09:50 +0000
Subject: Initial commit
Created from https://vercel.com/new
---
.../[websiteId]/segments/SegmentAddButton.tsx | 21 ++++++
.../[websiteId]/segments/SegmentDeleteButton.tsx | 60 +++++++++++++++
.../[websiteId]/segments/SegmentEditButton.tsx | 37 ++++++++++
.../[websiteId]/segments/SegmentEditForm.tsx | 86 ++++++++++++++++++++++
.../[websiteId]/segments/SegmentsDataTable.tsx | 24 ++++++
.../websites/[websiteId]/segments/SegmentsPage.tsx | 16 ++++
.../[websiteId]/segments/SegmentsTable.tsx | 38 ++++++++++
.../(main)/websites/[websiteId]/segments/page.tsx | 12 +++
8 files changed, 294 insertions(+)
create mode 100644 src/app/(main)/websites/[websiteId]/segments/SegmentAddButton.tsx
create mode 100644 src/app/(main)/websites/[websiteId]/segments/SegmentDeleteButton.tsx
create mode 100644 src/app/(main)/websites/[websiteId]/segments/SegmentEditButton.tsx
create mode 100644 src/app/(main)/websites/[websiteId]/segments/SegmentEditForm.tsx
create mode 100644 src/app/(main)/websites/[websiteId]/segments/SegmentsDataTable.tsx
create mode 100644 src/app/(main)/websites/[websiteId]/segments/SegmentsPage.tsx
create mode 100644 src/app/(main)/websites/[websiteId]/segments/SegmentsTable.tsx
create mode 100644 src/app/(main)/websites/[websiteId]/segments/page.tsx
(limited to 'src/app/(main)/websites/[websiteId]/segments')
diff --git a/src/app/(main)/websites/[websiteId]/segments/SegmentAddButton.tsx b/src/app/(main)/websites/[websiteId]/segments/SegmentAddButton.tsx
new file mode 100644
index 0000000..7b70fee
--- /dev/null
+++ b/src/app/(main)/websites/[websiteId]/segments/SegmentAddButton.tsx
@@ -0,0 +1,21 @@
+import { useMessages } from '@/components/hooks';
+import { Plus } from '@/components/icons';
+import { DialogButton } from '@/components/input/DialogButton';
+import { SegmentEditForm } from './SegmentEditForm';
+
+export function SegmentAddButton({ websiteId }: { websiteId: string }) {
+ const { formatMessage, labels } = useMessages();
+
+ return (
+ }
+ label={formatMessage(labels.segment)}
+ variant="primary"
+ width="800px"
+ >
+ {({ close }) => {
+ return ;
+ }}
+
+ );
+}
diff --git a/src/app/(main)/websites/[websiteId]/segments/SegmentDeleteButton.tsx b/src/app/(main)/websites/[websiteId]/segments/SegmentDeleteButton.tsx
new file mode 100644
index 0000000..bb52a22
--- /dev/null
+++ b/src/app/(main)/websites/[websiteId]/segments/SegmentDeleteButton.tsx
@@ -0,0 +1,60 @@
+import { ConfirmationForm } from '@/components/common/ConfirmationForm';
+import { useDeleteQuery, useMessages } from '@/components/hooks';
+import { Trash } from '@/components/icons';
+import { DialogButton } from '@/components/input/DialogButton';
+import { messages } from '@/components/messages';
+
+export function SegmentDeleteButton({
+ segmentId,
+ websiteId,
+ name,
+ onSave,
+}: {
+ segmentId: string;
+ websiteId: string;
+ name: string;
+ onSave?: () => void;
+}) {
+ const { formatMessage, labels, FormattedMessage } = useMessages();
+ const { mutateAsync, isPending, error, touch } = useDeleteQuery(
+ `/websites/${websiteId}/segments/${segmentId}`,
+ );
+
+ const handleConfirm = async (close: () => void) => {
+ await mutateAsync(null, {
+ onSuccess: () => {
+ touch('segments');
+ onSave?.();
+ close();
+ },
+ });
+ };
+
+ return (
+ }
+ title={formatMessage(labels.confirm)}
+ variant="quiet"
+ width="600px"
+ >
+ {({ close }) => (
+ {name},
+ }}
+ />
+ }
+ isLoading={isPending}
+ error={error}
+ onConfirm={handleConfirm.bind(null, close)}
+ onClose={close}
+ buttonLabel={formatMessage(labels.delete)}
+ buttonVariant="danger"
+ />
+ )}
+
+ );
+}
diff --git a/src/app/(main)/websites/[websiteId]/segments/SegmentEditButton.tsx b/src/app/(main)/websites/[websiteId]/segments/SegmentEditButton.tsx
new file mode 100644
index 0000000..5c56cf1
--- /dev/null
+++ b/src/app/(main)/websites/[websiteId]/segments/SegmentEditButton.tsx
@@ -0,0 +1,37 @@
+import { useMessages } from '@/components/hooks';
+import { Edit } from '@/components/icons';
+import { DialogButton } from '@/components/input/DialogButton';
+import type { Filter } from '@/lib/types';
+import { SegmentEditForm } from './SegmentEditForm';
+
+export function SegmentEditButton({
+ segmentId,
+ websiteId,
+ filters,
+}: {
+ segmentId: string;
+ websiteId: string;
+ filters?: Filter[];
+}) {
+ const { formatMessage, labels } = useMessages();
+
+ return (
+ }
+ title={formatMessage(labels.segment)}
+ variant="quiet"
+ width="800px"
+ >
+ {({ close }) => {
+ return (
+
+ );
+ }}
+
+ );
+}
diff --git a/src/app/(main)/websites/[websiteId]/segments/SegmentEditForm.tsx b/src/app/(main)/websites/[websiteId]/segments/SegmentEditForm.tsx
new file mode 100644
index 0000000..c3529d9
--- /dev/null
+++ b/src/app/(main)/websites/[websiteId]/segments/SegmentEditForm.tsx
@@ -0,0 +1,86 @@
+import {
+ Button,
+ Form,
+ FormButtons,
+ FormField,
+ FormSubmitButton,
+ Label,
+ Loading,
+ TextField,
+} from '@umami/react-zen';
+import { useMessages, useUpdateQuery, useWebsiteSegmentQuery } from '@/components/hooks';
+import { FieldFilters } from '@/components/input/FieldFilters';
+import { messages } from '@/components/messages';
+
+export function SegmentEditForm({
+ segmentId,
+ websiteId,
+ filters = [],
+ showFilters = true,
+ onSave,
+ onClose,
+}: {
+ segmentId?: string;
+ websiteId: string;
+ filters?: any[];
+ showFilters?: boolean;
+ onSave?: () => void;
+ onClose?: () => void;
+}) {
+ const { data } = useWebsiteSegmentQuery(websiteId, segmentId);
+ const { formatMessage, labels, getErrorMessage } = useMessages();
+
+ const { mutateAsync, error, isPending, touch, toast } = useUpdateQuery(
+ `/websites/${websiteId}/segments${segmentId ? `/${segmentId}` : ''}`,
+ {
+ type: 'segment',
+ },
+ );
+
+ const handleSubmit = async (formData: any) => {
+ await mutateAsync(formData, {
+ onSuccess: async () => {
+ toast(formatMessage(messages.saved));
+ touch('segments');
+ onSave?.();
+ onClose?.();
+ },
+ });
+ };
+
+ if (segmentId && !data) {
+ return ;
+ }
+
+ return (
+
+ );
+}
diff --git a/src/app/(main)/websites/[websiteId]/segments/SegmentsDataTable.tsx b/src/app/(main)/websites/[websiteId]/segments/SegmentsDataTable.tsx
new file mode 100644
index 0000000..c1ba82e
--- /dev/null
+++ b/src/app/(main)/websites/[websiteId]/segments/SegmentsDataTable.tsx
@@ -0,0 +1,24 @@
+import { DataGrid } from '@/components/common/DataGrid';
+import { useWebsiteSegmentsQuery } from '@/components/hooks';
+import { SegmentAddButton } from './SegmentAddButton';
+import { SegmentsTable } from './SegmentsTable';
+
+export function SegmentsDataTable({ websiteId }: { websiteId?: string }) {
+ const query = useWebsiteSegmentsQuery(websiteId, { type: 'segment' });
+
+ const renderActions = () => {
+ return ;
+ };
+
+ return (
+
+ {({ data }) => }
+
+ );
+}
diff --git a/src/app/(main)/websites/[websiteId]/segments/SegmentsPage.tsx b/src/app/(main)/websites/[websiteId]/segments/SegmentsPage.tsx
new file mode 100644
index 0000000..cbe7a1c
--- /dev/null
+++ b/src/app/(main)/websites/[websiteId]/segments/SegmentsPage.tsx
@@ -0,0 +1,16 @@
+'use client';
+import { Column } from '@umami/react-zen';
+import { WebsiteControls } from '@/app/(main)/websites/[websiteId]/WebsiteControls';
+import { Panel } from '@/components/common/Panel';
+import { SegmentsDataTable } from './SegmentsDataTable';
+
+export function SegmentsPage({ websiteId }) {
+ return (
+
+
+
+
+
+
+ );
+}
diff --git a/src/app/(main)/websites/[websiteId]/segments/SegmentsTable.tsx b/src/app/(main)/websites/[websiteId]/segments/SegmentsTable.tsx
new file mode 100644
index 0000000..4dbe511
--- /dev/null
+++ b/src/app/(main)/websites/[websiteId]/segments/SegmentsTable.tsx
@@ -0,0 +1,38 @@
+import { DataColumn, DataTable, type DataTableProps, Row } from '@umami/react-zen';
+import Link from 'next/link';
+import { SegmentDeleteButton } from '@/app/(main)/websites/[websiteId]/segments/SegmentDeleteButton';
+import { SegmentEditButton } from '@/app/(main)/websites/[websiteId]/segments/SegmentEditButton';
+import { DateDistance } from '@/components/common/DateDistance';
+import { useMessages, useNavigation } from '@/components/hooks';
+
+export function SegmentsTable(props: DataTableProps) {
+ const { formatMessage, labels } = useMessages();
+ const { websiteId, renderUrl } = useNavigation();
+
+ return (
+
+
+ {(row: any) => (
+
+ {row.name}
+
+ )}
+
+
+ {(row: any) => }
+
+
+ {(row: any) => {
+ const { id, name } = row;
+
+ return (
+
+
+
+
+ );
+ }}
+
+
+ );
+}
diff --git a/src/app/(main)/websites/[websiteId]/segments/page.tsx b/src/app/(main)/websites/[websiteId]/segments/page.tsx
new file mode 100644
index 0000000..0d3faac
--- /dev/null
+++ b/src/app/(main)/websites/[websiteId]/segments/page.tsx
@@ -0,0 +1,12 @@
+import type { Metadata } from 'next';
+import { SegmentsPage } from './SegmentsPage';
+
+export default async function ({ params }: { params: Promise<{ websiteId: string }> }) {
+ const { websiteId } = await params;
+
+ return ;
+}
+
+export const metadata: Metadata = {
+ title: 'Segments',
+};
--
cgit v1.2.3